package catnet

import (
	"catlib/group"
	"net"
)

/*
						|---------------------------------------| Context.Conn
	TCP.Config => Go -> in:Conn:(ConnCall)ConnTCP => .ConnCall -> (Context)(NewContext()) => ConnCall
*/

// TCP 服务器实现
type TCP struct {
	config  *Config
	listen  *net.TCPListener
	ifClose bool
}

// Listen 创建链接
func (tcp *TCP) Listen(config *Config) (err error) {
	if tcp.ifClose {
		return nil
	}
	// 配置初始化
	config.init(func() interface{} {
		return &ConnTCP{
			Context:   group.NewContext(),
			ReadData:  make([]byte, 255),
			WriteData: make([]byte, 255),
		}
	})
	tcp.config = config
	// 创建服务器
	defer isRecover(&err)
	add, err := net.ResolveTCPAddr(config.Network, config.Address)
	isError(err)
	tcp.listen, err = net.ListenTCP(config.Network, add)
	isError(err)
	tcp.ifClose = true
	// 携程处理
	for tcp.ifClose {
		p := config.pool.Get()
		conn := p.Value().(*ConnTCP)
		// 得到链接
		conn.conn, err = tcp.listen.AcceptTCP()
		conn.ifClose = true
		if err != nil {
			p.Put() // 放回
		} else {
			// 携程处理
			config.group.Go(func(in group.Conn) {
				pd := in.Value().(group.PoolData)
				ct := pd.Value().(*ConnTCP)
				// 启动上下文
				ct.Go(config.ConnCall.ConnCall)
				ct.Run(pd)
				//config.ConnCall.ConnCall(ct)
				// 关闭服务器
				ct.Close()
				// 结束放回缓冲区
				pd.Put()
			}, p)
		}
	}
	return err
}

// Close 关闭链接
func (tcp *TCP) Close() (err error) {
	defer isRecover(&err)
	if tcp.ifClose {
		tcp.ifClose = false
		isError(tcp.listen.Close()) // 关闭服务器
		tcp.config.Close()          // 关闭调度
	}
	return nil
}

// ConnTCP TCP用户链接
type ConnTCP struct {
	group.Context
	conn      *net.TCPConn
	ifClose   bool
	ReadData  []byte // 读数据
	WriteData []byte // 写数据
}

// Close 关闭服务器
func (tcp *ConnTCP) Close() error {
	if tcp.ifClose {
		// 标记关闭
		tcp.ifClose = false
		// 关闭上下文
		tcp.Context.Close()
		// 关闭通信
		return tcp.conn.Close()
	}
	return nil
}

// 读数据
func (tcp *ConnTCP) Read() (b []byte, err error) {
	n, err := tcp.conn.Read(tcp.ReadData[0:])
	return tcp.ReadData[:n], err
}

// 写数据
func (tcp *ConnTCP) Write() (n int, err error) {
	return tcp.conn.Write(tcp.WriteData)
}
